package com.future.service.Impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.future.allUtils.enums.RoleEnum;
import com.future.allUtils.utils.CacheClient;
import com.future.allUtils.utils.RegexPatterns;
import com.future.allUtils.utils.SecurityUtils;
import com.future.controller.UserController;
import com.future.domain.*;
import com.future.domain.DTO.*;
import com.future.domain.vo.StudentBackEndVO;
import com.future.mapper.*;
import com.future.service.AdminService;
import com.future.service.ChatMemberService;
import com.future.service.ChatRoomService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import static com.future.allUtils.utils.RegexPatterns.*;

@Service
@Slf4j
public class AdminServiceImpl extends ServiceImpl<AdminMapper, User> implements AdminService {
    @Autowired
    private RoleMapper roleMapper;
    @Autowired
    private CertificationMapper certificationMapper;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private UserRoleMapper userRoleMapper;
    @Autowired
    private StudentClassMapper studentClassMapper;
    @Autowired
    private UserClassMapper userClassMapper;
    @Autowired
    private StudentClassAuthenticationMapper studentClassAuthenticationMapper;
    @Autowired
    private ChatRoomService chatRoomService;
    @Autowired
    private BCryptPasswordEncoder bCryptPasswordEncoder;
    @Autowired
    private CacheClient cacheClient;
    @Autowired
    private ChatRoomMapper chatRoomMapper;
    @Autowired
    private ChatMemberService chatMemberService;
    @Autowired
    private BCryptPasswordEncoder passwordEncoder;
    @Autowired
    private AdminMapper adminMapper;
    @Autowired
    private UserController user;


    /**
     * 教师获取班级学生列表（仅能查看自己任教的班级）
     */  @Override
    public Result getClassStudents( Integer pageNum, Integer pageSize, Long classId) {

         if (pageNum == null || pageNum <= 0 || pageSize == null || pageSize <= 0) {
            return Result.fail("分页参数无效，请提供有效的页码和每页条数");
        }
        if (classId == null || classId <= 0) {
            return Result.fail("班级ID无效，请提供有效的班级ID");
        }
        // 1. 获取当前登录教师ID
        Long currentUserId = SecurityUtils.getCurrentUserId();

        // 2. 验证该班级是否属于当前教师任教
        Long classIdByUserId = getClassIdByUserId(currentUserId);
        if (classIdByUserId ==  null){
            return Result.fail("无权访问其他班级学生信息");
        }
        if (!classIdByUserId.equals(classId)) {
            return Result.fail( "无权访问其他班级学生信息");
        }

        // 3. 执行分页查询（连表user_role筛选学生角色）
        try {
            Page<User> page = new Page<>(pageNum, pageSize);
            // 查询指定班级中具有学生角色的用户（连表user_role和user_class）
            Page<User> studentPage = userMapper.selectPage(page, new LambdaQueryWrapper<User>()
                    .inSql(User::getId,
                            "SELECT ur.user_id FROM user_role ur " +
                                    "JOIN user_class uc ON ur.user_id = uc.user_id " +
                                    "WHERE ur.role_id = " + RoleEnum.STUDENT.getRoleId() +  // 学生角色ID
                                    " AND uc.class_id = " + classId)  // 指定班级ID
                    .orderByAsc(User::getId));

            // 4. 使用 Hutool BeanUtil 批量转换 User -> UserBackEndDTO
            List<UserBackEndDTO> dtoList = studentPage.getRecords().stream()
                    .map(user -> {
                        // 核心：拷贝属性(支持同名属性自动映射)
                        UserBackEndDTO dto = BeanUtil.copyProperties(user, UserBackEndDTO.class);
                        // 特殊处理：属性名不一致则需要手动补充
                        dto.setAuthorIdStr(String.valueOf(user.getId()));
                        return dto;
                    })
                    .collect(Collectors.toList());

            // 5. 构建 DTO 分页对象（保留原分页信息）
            Page<UserBackEndDTO> dtoPage = new Page<>();
            dtoPage.setRecords(dtoList);       // 转换后的DTO列表
            dtoPage.setTotal(studentPage.getTotal()); // 总记录数
            dtoPage.setCurrent(studentPage.getCurrent()); // 当前页码
            dtoPage.setSize(studentPage.getSize());     // 每页条数
            dtoPage.setPages(studentPage.getPages());   // 总页数

            return Result.ok(dtoPage);
        } catch (Exception e) {
            log.error("查询班级学生失败", e);
            return Result.fail("查询学生信息失败");
        }
    }

    /**
     * 教师更新本班学生状态（仅能管理自己班级的学生）
     * @param studentId 学生ID
     * @param status 状态值（0：禁言，1：正常）
     */
    @Override
    @Transactional
    public Result updateClassStudentStatus(Long studentId, Integer status) {
        // 1. 校验状态合法性（与updateUserStatus保持一致）
        if (status != 0 && status != 1) {
            return Result.fail("状态值必须为0（禁用）或1（正常）");
        }

        // 2. 校验学生ID非空
        if (studentId == null) {
            return Result.fail("学生ID不能为空");
        }

        // 3. 校验学生存在性
        User student = baseMapper.selectById(studentId);
        if (ObjectUtils.isEmpty(student)) {
            return Result.fail("学生不存在");
        }

        // 4. 校验当前用户是否为教师角色
        Long currentTeacherId = SecurityUtils.getCurrentUserId();
        List<Role> userRoles = roleMapper.selectUserRolesByUserId(currentTeacherId);
        boolean isTeacher = userRoles.stream()
                .anyMatch(role -> "教师".equals(role.getRoleName()));
        if (!isTeacher) {
            return Result.fail("无权限操作，仅教师可管理学生");
        }

        // 5. 获取当前教师的班级ID（确保教师已分配班级）
        Long teacherClassId = getClassIdByUserId(currentTeacherId);
        if (teacherClassId == null) {
            return Result.fail("当前教师未分配班级，无法操作学生状态");
        }

// 6. 先校验学生是否分配班级（确保有班级）
        Long studentClassId = baseMapper.getClassIdByUserId(studentId);
        if (studentClassId == null) {
            return Result.fail("该学生未分配班级");  // 优先提示“无班级”
        }

        // 7. 再校验学生是否属于当前教师的班级（权限控制）
        Integer studentCount = userClassMapper.countByUserIdAndClassId(studentId, teacherClassId);
        if (studentCount == null || studentCount == 0) {
            return Result.fail("无权操作：该学生不属于您的班级");  // 再提示“不属于您的班级”
        }
        // 8. 更新学生状态（参考updateUserStatus的更新逻辑）
        try {
            User updateStudent = new User();
            updateStudent.setId(studentId);
            updateStudent.setStatus(status);
            baseMapper.updateById(updateStudent);
            // 清除用户信息缓存
            cacheClient.deleteByPattern("user:info:vo:" + studentId + ":*");
            return Result.ok("学生状态更新成功");
        } catch (Exception e) {
            return Result.fail("更新学生状态失败，请重试");
        }
    }
    /**
     * 教师更新本班学生信息（仅能修改自己班级的学生基本信息）
     * @param student 学生信息对象（需包含id及待更新字段）
     */
    @Override
    @Transactional
    public Result updateClassStudent(User student) {
        // 1. 校验学生ID非空
        if (student == null || student.getId() == null) {
            return Result.fail("学生ID不能为空");
        }
        Long studentId = student.getId();

        // 2. 校验学生存在性
        User existingStudent = baseMapper.selectById(studentId);
        if (ObjectUtils.isEmpty(existingStudent)) {
            return Result.fail("学生不存在");
        }

        // 3. 校验学生角色（通过user_role关联表查询角色，确保是学生角色）
        List<Role> studentRoles = roleMapper.selectUserRolesByUserId(studentId);
        boolean isStudent = studentRoles.stream()
                .anyMatch(role -> "学生".equals(role.getRoleName()));
        if (!isStudent) {
            return Result.fail("仅允许修改学生角色的用户信息");
        }

        // 4. 校验当前用户是否为教师角色
        Long currentTeacherId = SecurityUtils.getCurrentUserId();
        List<Role> userRoles = roleMapper.selectUserRolesByUserId(currentTeacherId);
        boolean isTeacher = userRoles.stream()
                .anyMatch(role -> "教师".equals(role.getRoleName()));
        if (!isTeacher) {
            return Result.fail("无权限操作，仅教师可修改学生信息");
        }

        // 5. 获取当前教师的班级ID（确保教师已分配班级）
        Long teacherClassId = getClassIdByUserId(currentTeacherId);
        if (teacherClassId == null) {
            return Result.fail("当前教师未分配班级，请联系管理员");
        }

        // 6. 获取学生的班级ID（确保学生属于某个班级）
        Long studentClassId = baseMapper.getClassIdByUserId(studentId);
        if (studentClassId == null) {
            return Result.fail("该学生未分配班级");
        }

        // 7. 校验学生是否属于当前教师的班级（核心权限控制）
        if (!teacherClassId.equals(studentClassId)) {
            return Result.fail("无权修改其他班级的学生信息");
        }

        // 8. 校验学生账号状态（封号账号不可修改）
        if (existingStudent.getStatus() == 3) {
            return Result.fail("该账号已被封号，无法修改信息");
        }

        // 9. 字段格式校验
        // 9.1 用户名校验
        if (student.getUsername() != null && !student.getUsername().trim().isEmpty()) {
            if (!student.getUsername().matches(RegexPatterns.USERNAME_REGEX)) {
                return Result.fail("用户名格式错误（2-16位，支持汉字、字母、数字、下划线）");
            }
        }

        // 9.2 性别校验
        if (student.getGender() != null) {
            if (!student.getGender().matches(RegexPatterns.GENDER_CHINESE_REGEX)) {
                return Result.fail("性别值必须为“未知”、“男”或“女”");
            }
        }

        // 9.3 个人介绍校验
        if (student.getBio() != null && student.getBio().length() > 500) {
            return Result.fail("个人介绍不能超过500个字符");
        }


        // 9.5 邮箱格式校验
        if (student.getEmail() != null && !student.getEmail().trim().isEmpty()) {
            if (!student.getEmail().matches(RegexPatterns.EMAIL_REGEX)) {
                return Result.fail("邮箱格式有误");
            }
        }

        // 9.6 手机号格式校验
        if (student.getPhone() != null && !student.getPhone().trim().isEmpty()) {
            if (!student.getPhone().matches(RegexPatterns.PHONE_REGEX)) {
                return Result.fail("手机号格式有误");
            }
        }

        // 9.7 身份证号格式校验
        if (student.getIdCard() != null && !student.getIdCard().trim().isEmpty()) {
            if (!student.getIdCard().matches(RegexPatterns.ID_CARD_REGEX)) {
                return Result.fail("身份证号格式有误");
            }
        }

        // 9.8 状态值校验
        if (student.getStatus() != null && student.getStatus() != 0 && student.getStatus() != 1) {
            return Result.fail("状态值必须为0（禁言）或1（正常）");
        }

        // 10. 构建更新对象（保留原始字段，仅更新传入的非空字段）
        User updateStudent = new User();
        BeanUtil.copyProperties(existingStudent, updateStudent); // 拷贝原始数据
        BeanUtil.copyProperties(student, updateStudent,
                CopyOptions.create().setIgnoreNullValue(true)); // 合并更新字段

        // 11. 密码处理（仅在传入新密码时更新）
        if (student.getPassword() != null && !student.getPassword().trim().isEmpty()) {
            updateStudent.setPassword(bCryptPasswordEncoder.encode(student.getPassword()));
        }

        // 12. 设置更新时间
        updateStudent.setUpdatedAt(LocalDateTime.now());

        // 13. 执行更新操作
        try {
            baseMapper.updateById(updateStudent);
            // 清除用户信息缓存
            cacheClient.deleteByPattern("user:info:vo:" + studentId + ":*");
            return Result.ok("学生信息更新成功");
        } catch (Exception e) {
            log.error("更新学生信息失败", e); // 补充异常日志
            return Result.fail("更新学生信息失败，请重试");
        }
    }
    /**
     * 超级管理员获取所有用户（分页）
     */
    @Override
    public Result getAllUsers(Integer pageNum, Integer pageSize) {
        // 1. 分页参数校验与默认值处理
        pageNum = (pageNum == null || pageNum < 1) ? 1 : pageNum;
        pageSize = (pageSize == null || pageSize < 1 || pageSize > 100) ? 10 : pageSize;

        try {
            // 2. 构建分页对象
            Page<User> page = new Page<>(pageNum, pageSize);

            // 3.只查询DTO需要的字段
            LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<User>()
                    .select(
                            User::getId,
                            User::getAccount,
                            User::getUsername,
                            User::getEmail,
                            User::getRealName,
                            User::getAddress,
                            User::getIdCard,
                            User::getPhone,
                            User::getAvatar,
                            User::getStatus,
                            User::getGender,
                            User::getBio,
                            User::getIsCertified
                    );

            // 4. 执行分页查询
            Page<User> userPage = baseMapper.selectPage(page, queryWrapper);

            // 5. 转换实体到DTO
            List<UserBackEndDTO> userBackEndDTOList = new ArrayList<>(userPage.getRecords().size());
            for (User user : userPage.getRecords()) {
                UserBackEndDTO userBackEndDTO = new UserBackEndDTO();
                BeanUtil.copyProperties(user, userBackEndDTO);

                userBackEndDTO.setAuthorIdStr(String.valueOf(user.getId()));
                userBackEndDTOList.add(userBackEndDTO);
            }

            // 6. 构建MyBatis-Plus风格的分页结果
            Page<UserBackEndDTO> resultPage = new Page<>();
            resultPage.setRecords(userBackEndDTOList);
            resultPage.setTotal(userPage.getTotal());
            resultPage.setPages(userPage.getPages());
            resultPage.setCurrent(userPage.getCurrent());
            resultPage.setSize(userPage.getSize());
            resultPage.setSearchCount(userPage.isSearchCount());

            return Result.ok(resultPage);
        } catch (Exception e) {
            log.error("超级管理员查询用户列表失败，pageNum: {}, pageSize: {}");
            return Result.fail("查询用户列表失败，请稍后重试");
        }
    }


    /**
     * 超级管理员更新用户状态
     */
    @Override
    @Transactional
    public Result updateUserStatus(Long userId, Integer status) {
        // 1. 校验状态合法性
        if (status != 0 && status != 1&&status!=3) {
            return Result.fail("状态值必须为0（禁言）或1（正常）或3（封号）");
        }

        // 2. 校验用户存在性
        User user = baseMapper.selectById(userId);
        if (ObjectUtils.isEmpty(user)) {
            return Result.fail("用户不存在");
        }

        // 3. 禁止禁用超级管理员自身
        Long currentAdminId = SecurityUtils.getCurrentUserId();
        if (userId.equals(currentAdminId) && status == 0) {
            return Result.fail("不能禁用当前登录的管理员账户");
        }

        // 4. 更新状态
        try {
            User updateUser = new User();
            updateUser.setId(userId);
            updateUser.setStatus(status);
            baseMapper.updateById(updateUser);
            // 清除用户信息缓存
            cacheClient.deleteByPattern("user:info:vo:" + userId + ":*");
            return Result.ok("状态更新成功");
        } catch (Exception e) {
            log.error("更新用户状态失败", e);
            return Result.fail("更新用户状态失败");
        }
    }

    /**
     * 超级管理员更新用户信息
     */
    @Override
    @Transactional
    public Result updateUser(User user) {
        // 1. 校验当前用户是否为超级管理员（权限控制）
        Long currentAdminId = SecurityUtils.getCurrentUserId();
        List<Role> adminRoles = roleMapper.selectUserRolesByUserId(currentAdminId);
        boolean isSuperAdmin = adminRoles.stream()
                .anyMatch(role -> "超级管理员".equals(role.getRoleName()));
        if (!isSuperAdmin) {
            return Result.fail("无权限操作,仅超级管理员可操作");
        }

        // 2. 校验用户ID是否有效且用户存在
        if (user.getId() == null) {
            return Result.fail("用户ID不能为空");
        }
        Long userId = user.getId();
        User existingUser = baseMapper.selectById(userId);
        if (ObjectUtils.isEmpty(existingUser)) {
            return Result.fail("用户不存在");
        }

        // 3. 字段格式校验（补充完整校验逻辑，与updateClassStudent保持一致）
        // 3.1 用户名校验
        if (user.getUsername() != null && !user.getUsername().trim().isEmpty()) {
            if (!user.getUsername().matches(RegexPatterns.USERNAME_REGEX)) {
                return Result.fail("用户名格式错误（2-16位，支持汉字、字母、数字、下划线）");
            }
        }

        // 3.2 性别校验
        if (user.getGender() != null) {
            if (!user.getGender().matches(RegexPatterns.GENDER_CHINESE_REGEX)) {
                return Result.fail("性别值必须为“未知”、“男”或“女”");
            }
        }

        // 3.3 个人介绍校验
        if (user.getBio() != null && user.getBio().length() > 500) {
            return Result.fail("个人介绍不能超过500个字符");
        }


        // 3.5 邮箱格式校验
        if (user.getEmail() != null && !user.getEmail().trim().isEmpty()) {
            if (!user.getEmail().matches(RegexPatterns.EMAIL_REGEX)) {
                return Result.fail("邮箱格式有误");
            }
        }

        // 3.6 手机号格式校验
        if (user.getPhone() != null && !user.getPhone().trim().isEmpty()) {
            if (!user.getPhone().matches(RegexPatterns.PHONE_REGEX)) {
                return Result.fail("手机号格式有误");
            }
        }

        // 3.7 身份证号格式校验
        if (user.getIdCard() != null && !user.getIdCard().trim().isEmpty()) {
            if (!user.getIdCard().matches(RegexPatterns.ID_CARD_REGEX)) {
                return Result.fail("身份证号格式有误");
            }
        }

        // 3.8 状态值校验
        if (user.getStatus() != null && user.getStatus() != 0 && user.getStatus() != 1 && user.getStatus() != 3) {
            return Result.fail("状态值必须为0（禁用）或1（正常）或3（封号）");
        }

        // 4. 构建安全更新对象（避免字段覆盖，复用updateClassStudent的对象拷贝逻辑）
        User updateUser = new User();
        BeanUtil.copyProperties(existingUser, updateUser); // 先拷贝原始用户数据
        BeanUtil.copyProperties(user, updateUser,
                CopyOptions.create().setIgnoreNullValue(true)); // 合并传入的非空字段

        // 5. 密码处理（仅在传入新密码时更新，应用于更新对象）
        if (user.getPassword() != null && !user.getPassword().trim().isEmpty()) {
            updateUser.setPassword(bCryptPasswordEncoder.encode(user.getPassword()));
        }

        // 6. 设置更新时间
        updateUser.setUpdatedAt(LocalDateTime.now());

        // 7. 执行更新操作
        try {
            baseMapper.updateById(updateUser);
            // 清除用户信息缓存
            cacheClient.deleteByPattern("user:info:vo:" + userId + ":*");
            return Result.ok("用户信息更新成功");
        } catch (Exception e) {
            log.error("更新用户信息失败", e);
            return Result.fail("更新用户信息失败，请重试");
        }
    }
    @Override
    public Long getClassIdByUserId(Long userId) {
        return baseMapper.getClassIdByUserId(userId);
    }

    @Override
    public Result getClassNumByClassId(Long classId) {
        // 1. 校验班级ID有效性
        if (classId == null || classId <= 0) {
            return Result.fail("班级ID无效，请提供有效的班级ID");
        }

        try {
            // 2. 统计指定班级中具有学生角色的用户数量（复用getClassStudents的连表逻辑）
            Long studentCount = userMapper.selectCount(new LambdaQueryWrapper<User>()
                    .inSql(User::getId,
                            "SELECT ur.user_id FROM user_role ur " +
                                    "JOIN user_class uc ON ur.user_id = uc.user_id " +
                                    "WHERE ur.role_id = " + RoleEnum.STUDENT.getRoleId() +  // 学生角色ID
                                    " AND uc.class_id = " + classId)  // 指定班级ID
            );

            return Result.ok(studentCount);
        } catch (Exception e) {
            log.error("查询班级学生数量失败", e);
            return Result.fail("查询班级学生数量失败");
        }
    }
    /**
     * 审核用户角色认证申请
     * @param certificationId 认证记录ID
     * @param status 审核状态：1-通过，2-拒绝
     * @param rejectReason 拒绝原因（状态为拒绝时必填）
     */
    @Override
    @Transactional
    public Result auditCertification(Long certificationId, Integer status, String rejectReason) {
        // 1. 校验审核状态参数合法性
        if (status == null || (status != 0 && status != 1)) {
            return Result.fail("审核状态无效，必须是0（拒绝）或1（通过）");
        }

        // 2. 拒绝时必须提供原因
        if (status == 0 && (rejectReason == null || rejectReason.trim().isEmpty())) {
            return Result.fail("拒绝审核时必须提供拒绝原因");
        }

        // 3. 查询认证记录是否存在
        Certification certification = certificationMapper.selectById(certificationId);
        if (certification == null) {
            return Result.fail("认证申请不存在或已被删除");
        }

        // 4. 检查是否处于待审核状态
        if (!"待审核".equals(certification.getStatus())) {
            return Result.fail("该申请已审核，无法重复操作");
        }

        // 5. 更新认证记录状态
        certification.setStatus(status == 0 ? "已拒绝" : "已通过");
        certification.setRejectReason(status == 0 ? rejectReason.trim() : "");
        int updateRows = certificationMapper.updateById(certification);

        if (updateRows > 0) {
            // 6. 审核通过时同步更新用户信息
            if (status == 1) {
                User user = userMapper.selectById(certification.getUserId());
                if (user == null) {
                    throw new RuntimeException("关联用户不存在，审核失败");
                }

                // 将角色名称转换为角色ID（需与RoleEnum匹配）
                RoleEnum roleEnum = RoleEnum.getByRoleName(certification.getRole());
                if (roleEnum == null) {
                    throw new RuntimeException("角色信息异常，审核失败");
                }

                UserRole userRole = new UserRole();
                userRole.setUserId(user.getId());
                userRole.setRoleId(roleEnum.getRoleId());
                userRole.setCreatedAt(LocalDateTime.now());
                userRoleMapper.insert(userRole);
                // 清除用户信息缓存
                cacheClient.deleteByPattern("user:info:vo:" + user.getId() + ":*");

            }
            return Result.ok("审核成功");
        } else {
            return Result.fail("审核失败，请重试");
        }
    }
    @Override
    public Result getPendingCertifications(Integer pageNum, Integer pageSize) {
        try {
            Page<Certification> page = new Page<>(pageNum, pageSize);
            LambdaQueryWrapper<Certification> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(Certification::getStatus, "待审核")
                    .orderByDesc(Certification::getAppliedAt);

            Page<Certification> certificationPage = certificationMapper.selectPage(page, queryWrapper);
            for(Certification certification:certificationPage.getRecords()){
                certification.setUserIdStr(String.valueOf(certification.getUserId()));
            }

            return Result.ok(certificationPage);
        } catch (Exception e) {
            return Result.fail("查询认证申请失败");
        }
    }

    @Override
    public Result getPendingStudentClassApplications(Integer pageNum, Integer pageSize) {
        try {
            // 1. 分页查询待审核申请记录
            Page<StudentClassAuthentication> page = new Page<>(pageNum, pageSize);
            LambdaQueryWrapper<StudentClassAuthentication> queryWrapper = new LambdaQueryWrapper<>();
            Long classId = getClassIdByUserId(SecurityUtils.getCurrentUserId());
            queryWrapper.eq(StudentClassAuthentication::getStatus, "待审核")
                    .eq(StudentClassAuthentication::getClassId , classId)
                    .orderByDesc(StudentClassAuthentication::getAppliedAt);
            Page<StudentClassAuthentication> applicationPage = studentClassAuthenticationMapper.selectPage(page, queryWrapper);

            // 2. 提取所有studentId，批量查询用户信息（避免N+1查询）
            List<StudentClassAuthentication> authList = applicationPage.getRecords();
            if (authList.isEmpty()) {
                return Result.ok(applicationPage); // 无数据直接返回
            }

            List<Long> studentIds = authList.stream()
                    .map(StudentClassAuthentication::getStudentId)
                    .distinct()
                    .collect(Collectors.toList());

            // 批量查询用户信息（使用userMapper）
            List<User> userList = userMapper.selectBatchIds(studentIds);
            Map<Long, User> userMap = userList.stream()
                    .collect(Collectors.toMap(User::getId, user -> user));

            // 3. 转换为包含用户信息的DTO
            List<StudentClassAuthDTO> dtoList = authList.stream()
                    .map(auth -> {
                        StudentClassAuthDTO dto = new StudentClassAuthDTO();
                        BeanUtil.copyProperties(auth, dto); // 拷贝申请记录基本信息

                        // 补充用户信息
                        User user = userMap.get(auth.getStudentId());
                        if (user != null) {
                            dto.setUsername(user.getUsername());
                            dto.setAccount(user.getAccount());
                            dto.setRealName(user.getRealName());
                            dto.setPhone(user.getPhone());
                        }
                        return dto;
                    })
                    .collect(Collectors.toList());

            // 4. 构建包含DTO的分页结果
            Page<StudentClassAuthDTO> resultPage = new Page<>(pageNum, pageSize);
            resultPage.setRecords(dtoList);
            resultPage.setTotal(applicationPage.getTotal());
            resultPage.setPages(applicationPage.getPages());
            resultPage.setCurrent(applicationPage.getCurrent());
            resultPage.setSize(applicationPage.getSize());

            return Result.ok(resultPage);

        } catch (Exception e) {
            log.error("查询班级申请失败", e);
            return Result.fail("查询班级申请失败");
        }
    }

    @Override
    @Transactional
    public Result auditStudentJoinClassApply(Long applyId, Integer status, String rejectReason) {
        // 1. 校验审核状态参数合法性
        if (status == null || (status != 0 && status != 1)) {
            return Result.fail("审核状态无效，必须是0（拒绝）或1（通过）");
        }

        // 2. 拒绝时必须提供原因
        if (status == 0 && (rejectReason == null || rejectReason.trim().isEmpty())) {
            return Result.fail("拒绝申请时必须提供拒绝原因");
        }

        // 3. 查询申请记录是否存在且为"加入班级"类型
        StudentClassAuthentication apply = studentClassAuthenticationMapper.selectById(applyId);
        if (apply == null) {
            return Result.fail("加入班级申请不存在或已被删除");
        }
        if (!"加入".equals(apply.getApplyType())) {
            return Result.fail("该申请非加入班级类型，无法审核");
        }

        // 4. 检查是否处于待审核状态
        if (!"待审核".equals(apply.getStatus())) {
            return Result.fail("该申请已审核，无法重复操作");
        }

        // 5. 获取当前审核人ID和角色
        Long reviewerId = SecurityUtils.getCurrentUserId();
        List<Role> reviewerRoles = roleMapper.selectUserRolesByUserId(reviewerId);
        boolean isAdmin = reviewerRoles.stream().anyMatch(role -> "超级管理员".equals(role.getRoleName()));
        boolean isTeacher = reviewerRoles.stream().anyMatch(role -> "教师".equals(role.getRoleName()));

        if (!isAdmin && !isTeacher) {
            return Result.fail("无权限审核班级申请，仅管理员和教师可操作");
        }

        // 6. 教师只能审核自己班级的申请
        if (isTeacher) {
            List<Long> teacherClassId = adminMapper.getClassIdByTeacherId(reviewerId);
            Set<Long> teacherClassIdSet = new HashSet<>(teacherClassId);

            if (!teacherClassIdSet.contains(apply.getClassId())) {
                return Result.fail("无权审核其他班级的申请");
            }
        }

        // 7. 更新申请记录状态
        apply.setStatus(status == 1 ? "已通过" : "已拒绝");
        apply.setRejectReason(status == 0 ? rejectReason.trim() : null);
        apply.setReviewerId(reviewerId);
        apply.setReviewedAt(LocalDateTime.now());
        int updateRows = studentClassAuthenticationMapper.updateById(apply);

        if (updateRows > 0) {
            // 8. 审核通过时添加学生到班级（加入班级的核心逻辑）
            if (status == 1) {
                Long studentId = apply.getStudentId();
                Long existingClassId = getClassIdByUserId(studentId); // 复用查询用户班级的方法
                if (existingClassId != null) {
                    return Result.fail("该学生已加入其他班级，无法重复加入");
                }
                // 检查是否已在班级中
                LambdaQueryWrapper<UserClass> userClassWrapper = new LambdaQueryWrapper<>();
                userClassWrapper.eq(UserClass::getUserId, apply.getStudentId())
                        .eq(UserClass::getClassId, apply.getClassId());

                if (userClassMapper.selectCount(userClassWrapper) > 0) {
                    return Result.fail("该学生已在班级中，无需重复添加");
                }

                // 添加到班级
                UserClass userClass = new UserClass();
                userClass.setUserId(apply.getStudentId());
                userClass.setClassId(apply.getClassId());
                userClass.setJoinedAt(LocalDateTime.now());
                userClassMapper.insert(userClass);
                //添加到班级聊天室
                Long classId = apply.getClassId();
                LambdaQueryWrapper<ChatRoom> chatQueryWrapper = new LambdaQueryWrapper<>();
                chatQueryWrapper.eq(ChatRoom::getClassId, classId);
                ChatRoom chatRoom = chatRoomMapper.selectOne(chatQueryWrapper);
                if(chatRoom!=null)
                {
                    Long chatRoomId = chatRoom.getId();
                    Long userId=apply.getStudentId();
                    boolean b = chatMemberService.insertMember(chatRoomId, userId);
                    if("true".equals(b)) {
                        log.info("成功添加用户到班级聊天室");
                    }
                }
            }
            cacheClient.deleteByPattern("user:info:vo:"+apply.getStudentId());
            return Result.ok("审核成功");
        } else {
            return Result.fail("审核失败，请重试");
        }
    }

    @Override
    @Transactional
    public Result auditStudentQuitClassApply(Long applyId, Integer status, String rejectReason) {
        // 1. 校验审核状态参数合法性（复用加入班级的校验逻辑）
        if (status == null || (status != 0 && status != 1)) {
            return Result.fail("审核状态无效，必须是0（拒绝）或1（通过）");
        }

        // 2. 拒绝时必须提供原因
        if (status == 0 && (rejectReason == null || rejectReason.trim().isEmpty())) {
            return Result.fail("拒绝申请时必须提供拒绝原因");
        }

        // 3. 查询申请记录是否存在且为"退出班级"类型
        StudentClassAuthentication apply = studentClassAuthenticationMapper.selectById(applyId);
        if (apply == null) {
            return Result.fail("退出班级申请不存在或已被删除");
        }
        if (!"退出".equals(apply.getApplyType())) {
            return Result.fail("该申请非退出班级类型，无法审核");
        }

        // 4. 检查是否处于待审核状态（复用现有逻辑）
        if (!"待审核".equals(apply.getStatus())) {
            return Result.fail("该申请已审核，无法重复操作");
        }

        // 5. 权限校验（与加入班级共用同一套权限逻辑）
        Long reviewerId = SecurityUtils.getCurrentUserId();
        List<Role> reviewerRoles = roleMapper.selectUserRolesByUserId(reviewerId);
        boolean isAdmin = reviewerRoles.stream().anyMatch(role -> "超级管理员".equals(role.getRoleName()));
        boolean isTeacher = reviewerRoles.stream().anyMatch(role -> "教师".equals(role.getRoleName()));

        if (!isAdmin && !isTeacher) {
            return Result.fail("无权限审核班级申请，仅管理员和教师可操作");
        }

        // 6. 教师只能审核自己班级的申请
        if (isTeacher) {
            List<Long> teacherClassId = adminMapper.getClassIdByTeacherId(reviewerId);
            Set<Long> teacherClassIdSet = new HashSet<>(teacherClassId);

            if (!teacherClassIdSet.contains(apply.getClassId())) {
                return Result.fail("无权审核其他班级的申请");
            }
        }

        // 7. 更新申请记录状态
        apply.setStatus(status == 1 ? "已通过" : "已拒绝");
        apply.setRejectReason(status == 0 ? rejectReason.trim() : null);
        apply.setReviewerId(reviewerId);
        apply.setReviewedAt(LocalDateTime.now());
        int updateRows = studentClassAuthenticationMapper.updateById(apply);

        if (updateRows > 0) {
            // 8. 审核通过时从班级中移除学生（退出班级的核心逻辑）
            if (status == 1) {
                // 从用户班级关联表中删除记录
                LambdaQueryWrapper<UserClass> userClassWrapper = new LambdaQueryWrapper<>();
                userClassWrapper.eq(UserClass::getUserId, apply.getStudentId())
                        .eq(UserClass::getClassId, apply.getClassId());

                userClassMapper.delete(userClassWrapper);
                //退出班级聊天室
                Long classId = apply.getClassId();
                LambdaQueryWrapper<ChatRoom> chatQueryWrapper = new LambdaQueryWrapper<>();
                chatQueryWrapper.eq(ChatRoom::getClassId, classId);
                ChatRoom chatRoom = chatRoomMapper.selectOne(chatQueryWrapper);
                if(chatRoom!=null)
                {
                    Long chatRoomId = chatRoom.getId();
                    Long userId = apply.getStudentId();
                    boolean b = chatMemberService.removeRoomMember(userId, chatRoomId);
                    if("true".equals(b))
                    {
                        log.info("成功从聊天室中移除用户");
                    }
                }
            }
            cacheClient.deleteByPattern("user:info:vo:"+apply.getStudentId());
            return Result.ok("审核成功");
        } else {
            return Result.fail("审核失败，请重试");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result contributeClass(StudentClassDTO dto) {
        // 校验参数是否为空
        if (dto.getStudentClassName() == null ||dto.getGrade() == null) {
            return Result.fail("参数不能为空");
        }

        // 截取className的前两个字符
        String firstTwoChars = dto.getStudentClassName().substring(0, 2);
        // 比较截取的结果与grade是否相同
        if (!firstTwoChars.equals(dto.getGrade())){
            return Result.fail("班级与年级不匹配");
        }

        //查询班级是否存在
        LambdaQueryWrapper<StudentClass> lqw = new LambdaQueryWrapper<>();
        lqw.eq(StudentClass::getClassName,dto.getStudentClassName());
        StudentClass studentClass = studentClassMapper.selectOne(lqw);
        if (studentClass != null){
            return Result.fail("班级已存在");
        }

        //添加班级
        StudentClass studentClass1 = new StudentClass();
        studentClass1.setClassName(dto.getStudentClassName());
        studentClass1.setGrade(dto.getGrade());
        studentClass1.setTeacherId(SecurityUtils.getCurrentUserId());
        studentClass1.setCreatedAt(LocalDateTime.now());
        studentClass1.setUpdatedAt(LocalDateTime.now());
        studentClassMapper.insert(studentClass1);

        //班主任加入班级
        UserClass userClass = new UserClass();
        userClass.setUserId(SecurityUtils.getCurrentUserId());
        userClass.setClassId(studentClass1.getId());
        userClass.setJoinedAt(LocalDateTime.now());
        int insert = userClassMapper.insert(userClass);
        if(insert==0){
            throw new RuntimeException("班主任添加班级失败");
        }
        cacheClient.deleteByPattern("user:info:vo:"+SecurityUtils.getCurrentUserId());

        //创建班级群聊
        Long classId = studentClass1.getId();
        Result result = chatRoomService.creatChatRoom(classId);
        return Result.ok(result);
    }

    @Override
    public Result addStudent(RegisterUserDTO dto) {
        //邮箱格式校验
        if(!dto.getEmail().matches(EMAIL_REGEX)){
            return Result.fail("邮箱格式有误,请输入正确邮箱");
        }
        //密码格式校验
        if(!dto.getPassword().matches(PASSWORD_REGEX)){
            return Result.fail("密码格式有误,应为8-20位字母、数字、" +
                    "特殊字符，至少包含大小写字母、数字、特殊字符中的两种");
        }

        //账号格式校验
        if(!dto.getAccount().matches(ACCOUNT_REGEX)){
            return Result.fail("账号格式有误,应为6-20位字母、数字、" +
                    "特殊字符，只能包含字母、数字、特殊字符,不以数字开头");
        }

        //通过枚举校验角色是否有效
        String roleName = dto.getRole();
        RoleEnum roleEnum = RoleEnum.getByRoleName(roleName);
        if (roleEnum == null) {
            return Result.fail("无效的角色类型，请选择：学生、教师、心理医生");
        }

        // 2. 校验邮箱是否已存在
        LambdaQueryWrapper<User> emailWrapper = new LambdaQueryWrapper<>();
        emailWrapper.eq(User::getEmail, dto.getEmail());
        if(userMapper.selectCount(emailWrapper)>0){
            return Result.fail("邮箱已被注册，请更换邮箱");
        }

       //校验账号是否已存在
        LambdaQueryWrapper<User> accountWrapper = new LambdaQueryWrapper<>();
        accountWrapper.eq(User::getAccount, dto.getAccount());
        if (userMapper.selectCount(accountWrapper) > 0) {
            return Result.fail("账号已被注册，请更换账号");
        }


        User user = new User();
        BeanUtil.copyProperties(dto, user);
        user.setPassword(passwordEncoder.encode(dto.getPassword())); // 使用BCrypt加密密码

        // 4. 插入数据库
        int insert = userMapper.insert(user);

        // 5.将user的身份插入user_role表
        //通过枚举获取角色ID，插入user_role表
        UserRole userRole = new UserRole();
        userRole.setUserId(user.getId());
        userRole.setRoleId(roleEnum.getRoleId());
        userRole.setCreatedAt(LocalDateTime.now());
        userRoleMapper.insert(userRole);
        return insert > 0 ? Result.ok("添加成功") : Result.fail("添加失败");
    }

    @Override
    public Result getStudent(Integer pageNum, Integer pageSize) {
        // 处理分页参数默认值
        pageNum = pageNum == null ? 1 : pageNum;
        pageSize = pageSize == null ? 10 : pageSize;

        // 创建分页对象
        Page<User> page = new Page<>(pageNum, pageSize);

        // 使用AdminMapper查询学生角色的用户
        // 这里使用XML配置的方式实现联表查询
        Page<StudentBackEndVO> userPage = adminMapper.selectStudentsPage(page);

        return Result.ok(userPage);
    }
}